Skip to content

Add support for JUnit6#1659

Draft
schulzjo-tng wants to merge 7 commits into
mainfrom
feature/junit6-with-test-coverage
Draft

Add support for JUnit6#1659
schulzjo-tng wants to merge 7 commits into
mainfrom
feature/junit6-with-test-coverage

Conversation

@schulzjo-tng

@schulzjo-tng schulzjo-tng commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@arukiidou

arukiidou commented Jul 9, 2026

Copy link
Copy Markdown

Part 1 and Part 2 are almost identical.
If possible, I recommend cherry-picking from Part 2.

Only the following three things should be different:

  • It starts over again from the addition of the shared tests
  • The commits have been split into smaller ones to make things easier
  • example-test has been added

@schulzjo-tng schulzjo-tng force-pushed the feature/junit6-with-test-coverage branch 2 times, most recently from 25a25d8 to c9660f2 Compare July 9, 2026 14:33
@schulzjo-tng schulzjo-tng force-pushed the feature/junit6-with-test-coverage branch 2 times, most recently from 9998433 to dabea23 Compare July 10, 2026 13:57
Comment on lines +619 to +621
Stream<T> FrozenRulesTest(Class<?> frozenRulesTestClass) {
return frozenRulesExpectedTestFailures(frozenRulesTestClass).toDynamicTests();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no aroundTestInvoke is needed for JUnit6 - it was only needed on Java 8 and 11, which JUnit6 doesn't support

Comment on lines -62 to -79
def addCleanThirdPartyTask = {
// These files are already relocated into archunit.jar, so they're transitively available
tasks.create(name: 'removeDuplicateThirdParty', type: Jar, dependsOn: shadowJar) {
exclude "${thirdPartyRelocationPackage.replace('.', '/')}/**"

File tempPath = tempJar(jar.archiveFile.get().getAsFile())
File jarPath = shadowJar.archiveFile.get().getAsFile()
inputs.file(jarPath)
from zipTree(jarPath)
archiveFileName = tempPath.name

doLast {
assert jarPath.delete()
assert tempPath.renameTo(jarPath)
}
}
finishArchive.dependsOn removeDuplicateThirdParty
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This task caused build failures on Windows. After some investigation, I concluded that it is no longer needed - the existing dependencies.exclude() make this transformation an identity operation. Also, there is test coverage for missing exclude statements (see :checkArtifact), so we can't accidentally publish a release where the problem that this code meant to address is present.

Set<SingleTest> result = new HashSet<>();
for (int i = 0; i < classNames.size(); i++) {
result.add(new SingleTest(classNames.get(i), testNames.get(i)));
result.add(new SingleTest(toSimpleClassName(classNames.get(i)), testNames.get(i)));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was needed due to a change in the test reports (major version upgrade)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which should be isolated in a separate commit, as it's entirely unrelated to Add JUnit6 test coverage. 😉

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2c2fcce

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. It is a necessary prerequisite since the old version of Surefire didn't work with JUnit 6.

Comment on lines +196 to +200
[prepareMavenTest, executeRules, verifyRules, cleanUpMavenTest, runMavenTest].each { taskName ->
tasks[taskName].onlyIf("requires Java ${config.minimumJavaVersion} or higher") {
config.supports(integrationTestJavaVersion)
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot run the JUnit6 tasks on Java 8 and 11, hence this new block

Comment on lines +129 to +130
.replace('#{mavenSurefirePluginVersion}', "${mavenSurefirePlugin.version}")
.replace('#{mavenCompilerPluginVersion}', "${mavenCompilerPlugin.version}")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, the plugins are updated via dependabot

surefireExampleConfiguration: '<groups>example</groups>',
archunitTestArtifact: 'archunit-junit5',
additionalDependencies: """
def testConfigFor = (TestType testType) -> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This restructure makes it harder to forget adding a case for a new JUnit version

Comment on lines -118 to -146
public static class ArchUnitProductionCode implements ImportOption {
private static final Set<String> SOURCE_ROOTS = sourceRootsOf(
ArchConfiguration.class,
ArchUnitRunner.class,
ArchTag.class,
FieldSelector.class,
ArchUnitTestEngine.class);

private static Set<String> sourceRootsOf(Class<?>... classes) {
ImmutableSet.Builder<String> result = ImmutableSet.builder();
for (Class<?> c : classes) {
String classFile = "/" + c.getName().replace('.', '/') + ".class";
String file = c.getResource(classFile).getFile();
result.add(file.substring(0, file.indexOf(classFile)));
}
return result.build();
}

@Override
public boolean includes(Location location) {
boolean include = false;
for (String sourceRoot : SOURCE_ROOTS) {
if (location.contains(sourceRoot)) {
include = true;
}
}
return include && DO_NOT_INCLUDE_TESTS.includes(location);
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now decide on a subproject basis if something is "production code"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to archunit-self-test/src/main/java/com/tngtech/archunit/ArchUnitExampleArchitectureRules.java with too many changes

Comment on lines -12 to -21
implementation project(path: ':archunit')
implementation project(path: ':archunit-junit4')
implementation project(path: ':archunit-junit5')
implementation project(path: ':archunit-junit5-engine')
implementation project(path: ':archunit-example:example-plain')
implementation project(path: ':archunit-example:example-plain', configuration: 'tests')
implementation project(path: ':archunit-example:example-junit4', configuration: 'tests')
implementation project(path: ':archunit-example:example-junit5', configuration: 'tests')

testImplementation project(path: ':archunit-junit5')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The self-tests are now imported by those packages. This was necessary because classes between archunit-junit5 and archunit-junit6 would collide, and only one of them would get tested

@@ -0,0 +1,29 @@
sourceSets {
archTest {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use a separate source set because the self-tests need a specific archunit-junit* version, which would otherwise pollute the test classpath or interfere with other tests

arukiidou and others added 5 commits July 10, 2026 16:32
Issue: #1556

Signed-off-by: junya koyama <arukiidou@yahoo.co.jp>
Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
- Required because the previous setting was unable to test junit5-engine and junit6-engine at the same time

Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
This task caused build failures on Windows. After some investigation,
I concluded that it is no longer needed - the existing `dependencies.exclude()`
make this transformation an identity operation. Also, there is test coverage
for missing `exclude` statements (see `:checkArtifact`), so we can't accidentally
publish a release where the problem that this code meant to address is present.

Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
@schulzjo-tng schulzjo-tng force-pushed the feature/junit6-with-test-coverage branch from dabea23 to 75512aa Compare July 10, 2026 14:32
@@ -20,13 +20,12 @@ task ensureReleaseCheckUpToDate {
VersionCatalog versionCatalog = versionCatalogs.named("libs")
def dependencies = versionCatalog.libraryAliases.collect { versionCatalog.findLibrary(it).get().get() }
def matchingProjectDependency = dependencies.find {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old logic no longer worked on dependencies to junit-platform-launcher which would get mixed up

Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
Comment on lines +212 to +213
def junit5VintageEngine = libs.junit5VintageEngine.get()
def junit6VintageEngine = libs.junit6VintageEngine.get()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those could be moved to the case TestType.JUNIT5 / JUNIT6 blocks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

01f4f01

Set<SingleTest> result = new HashSet<>();
for (int i = 0; i < classNames.size(); i++) {
result.add(new SingleTest(classNames.get(i), testNames.get(i)));
result.add(new SingleTest(toSimpleClassName(classNames.get(i)), testNames.get(i)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which should be isolated in a separate commit, as it's entirely unrelated to Add JUnit6 test coverage. 😉

testImplementation project(path: ':archunit-example:example-junit6', configuration: 'tests')

testRuntimeOnly project(path: ':archunit-junit6-engine')
// TODO still up-to-date?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

… be allow-listed

Signed-off-by: Dr. Jonathan Schulz <jonathan.schulz@tngtech.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants